#if 0
/*
 * start parallel dns & identd lookup
 */

#include "ircid.h"

static void	finish_auth(auth_info *ai)
{
	if (ai->dns_state < 2) {
		dns_cancel(ai->q);
		ai->dns_state = 2;
	}

	/* not until the identd is done */
	if (!ai->ident_state)
		return;
	if (ai->cb)
		ai->cb(ai, ai->data);
	zfree(ai);
}

static void	dns_forward(struct dns_ctx *ctx, void *results, void *data)
{
	auth_info *ai = data;
	struct dns_rr_a6 *v4 = results;
	assert(ai->dns_state == 1);
	ai->dns_state = 2;
#ifdef IPV6
	struct dns_rr_a6 *v6 = results;

	/* no results, bye .. */
	if (!results)
		return finish_auth(ai);

	if (ai->ipv6) {
		for (i = 0; i < v6->dnsa6_nrr; i++) {
			if (!memcmp(&v6->dnsa6_addr[i], ai->ip, 16)) {
				/* found matching entry! */
				strcpy(ai->hostname, v6->dnsa6_qname);
				break;
			}
		}
		/* no match */
		finish_auth(ai);
		return;
	}
#endif
	for (i = 0; i < v4->dnsa4_nrr; i++) {
		if (!memcmp(&v6->dnsa4_addr[i], ai->ip, 4)) {
			/* found matching entry! */
			strcpy(ai->hostname, v4->dnsa4_qname);
			break;
		}
	}
	finish_auth(ai);
}

void	dns_reverse(struct dns_ctx *ctx, struct dns_rr_ptr *result, void *data)
{
	auth_info *ai = data;

	ai->q = NULL;

	/* nothing to be done */
	if (!result || !result->dnsptr_nrr) {
		ai->dns_state = 2;
		finish_auth(ai);
	}
	ai->dns_state = 1; /* will be doing forward now */

	/* we dont care about the other ptrs, pick up the first one */
#ifdef INET6
	if (ai->ipv6) {
		dns_submit_a6(ctx, result->dnsptr_ptr[0], 0, (void*) dns_forward, data);
	} else
#endif
	dns_submit_a4(ctx, result->dnsptr_ptr[0], 0, (void*)dns_forward, data);
}

static void	on_ident_response(ebb_connection *c, char *buf, int len)
{
	auth_info *ai = c->data;
	char *tail = ai->id + strlen(ai->id);
	if (strlen(ai->id) + len + 1 >= sizeof(ai->id))
		goto done;
	memcpy(tail, buf, len);
	tail[len] = 0;
	if (!(p = strchr(tail, '\n')))
		return;
done:
	ai->ident_state = 1;
	ebb_connection_schedule_close(c);
}

static void	on_ident_close(ebb_connection *c)
{
	auth_info *ai = c->data;
	finish_auth(ai);
}

static int	ai_on_timeout(struct ev_loop *loop, ev_timer *w, int revents)
{
	auth_info *ai = w->data;
	auth_stop(ai);
}

/* fire it up! */
auth_info *auth_start(ev_loop *loop, struct SOCKADDR_IN *server, struct SOCKADDR_IN *client, int timeout)
{
	int port;
	auth_info *ai;
	zalloc(ai);
	ebb_connection_init(&ai->c);
	ai->c.data = ai;
	ai->c.on_data = on_ident_response;
	ai->c.on_close = on_ident_close;
	ai->c.loop = loop;

	/* start ident lookup */
	sprintf(ai->wbuf, "%d , %d\n", ntohs(client->sin_port), ntohs(server->sin_port));
	ebb_tcp_client(&ai->c, inetntop(client), 113);
	ebb_connection_write(&ai->c, ai->wbuf, strlen(ai->wbuf), NULL);

	/* start reverse lookup */
#if INET6
	/* looking up v4 */
	if (IN6_IS_ADDR_V4MAPPED(&client->sin_addr)) {
		memcpy(ai->ip, (void *) (((char *)&client->sin_addr) + 12));
		dns_submit_a4ptr(ctx, ai->ip, dns_reverse, ai);
	} else {
		memcpy(ai->ip, &client->sin_addr, 16);
		ai->ipv6 = 1;
		dns_submit_a6ptr(ctx, client->sin_addr, dns_reverse, ai);
	}
#else
	memcpy(ai->ip, &client->sin_addr, 4);
	dns_submit_a4ptr(ctx, ai->ip, dns_reverse, ai);
#endif
	ev_timer_init(&ai->timeout, auth_on_timeout, timeout, 0.);
	return ai;
}

auth_info *auth_stop(auth_info *ai)
{
	ai->ident_state = 1;
	ebb_connection_schedule_close(c);
	finish_auth(ai);
}

ev_io udp_sock;

static	void on_udp(struct ev_loop *loop, ev_io *watcher, int revents)
{
	dns_ioevent(ctx, (int)ev_now(loop));
}

void	auth_init()
{
	ctx = &dns_defctx;
	udns_init(ctx, 1);
	ev_init(&udp_sock, on_udp);
	ev_io_set(&udp_sock, dns_sock(ctx), EV_READ);
}

#endif
